﻿using System;
using System.Linq;

using Buddy.BehaviorTree;
using Buddy.Common;
using Buddy.CommonBot;
using Buddy.Swtor;
using Buddy.Swtor.Objects;

using WingIt;
using WingIt.Dynamics;
using WingIt.Routines.Mirrors;

namespace WingIt.Routines
{
    [RevisionControlId("$Id: Marksmanship_Sharpshooter.cs 697 2012-08-13 19:30:43Z Chinajade $")]
    public class SniperMarksmanship_GunslingerSharpshooter : MirrorRoutine
    {
        // MAINTAINERS NOTES:
        // * You will notice that lambda expression argument names are unique (e.g., "darkWardOn", "darkWardWhen", "joltWhen"),
        //   instead of generic (e.g., "ctx", "ret", "on", "doWhen", "castWhen").  PLEASE honor this convention!
        //   This allows us to quickly localize problems when looking at user's logs.  When the BehaviorTree encounters an exception
        //   (e.g., "object not found"), the location where an exception is thrown is identifiable only through the name
        //   of the lambda expression argument.  Such is the nature of BehaviorTrees.

        [Behavior(BehaviorType.Pull)]
        [Class(CharacterClass.Agent, AdvancedClass.Sniper, SkillTreeId.SniperMarksmanship)]
        [Class(CharacterClass.Smuggler, AdvancedClass.Gunslinger, SkillTreeId.GunslingerSharpshooter)]
        public static Composite SniperMarksmanship_GunslingerSharpshooter_Pull()
        {
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                CreateBTPS.BWcoreFixup_WaitForHarvestComplete(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                //TODO: Delete this once MoveAndCoverForTarget() verified to work.
                //CreateBTPS.MoveWithinRangeAndLoS(target => MyTarget, Global.Distance.Ranged),
                //Cast("Crouch", crouchOn => Me),
                CreateBTPS.MoveAndCoverForTarget(myTarget => MyTarget),
                new Decorator(whenCrowdControlNeeded => CCTarget != null,
                    Cast("Slice Droid", sliceDroidOn => CCTarget, sliceDroidWhen => TargetSelect.ViableTargetList().FirstOrDefault(t => t.HasMirrorDebuffStacks("Slice Droid")) == null)),
				Cast("Shatter Shot", shatterShotWhen => !MyTarget.HasMirrorDebuff("Armor Reduced (Physical)")), // Flourish Shot
				Cast("Explosive Probe")
                );
        }

        [Behavior(BehaviorType.Combat)]
        [Class(CharacterClass.Agent, AdvancedClass.Sniper, SkillTreeId.SniperMarksmanship)]
        [Class(CharacterClass.Smuggler, AdvancedClass.Gunslinger, SkillTreeId.GunslingerSharpshooter)]
        public static Composite SniperMarksmanship_GunslingerSharpshooter_Combat()
        {
            return new PrioritySelector(
                LazyRaider.CreateBTPS_NotifyAndShortCircuitWhenCombatDisabled(),
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),

                //TODO: Delete this once MoveAndCoverForTarget() verified to work.
                //CreateBTPS.StopWithinRangeAndLoS(target => MyTarget, Global.Distance.Ranged),
                //Cast("Crouch", crouchOn => Me),
                CreateBTPS.MoveAndCoverForTarget(myTarget => MyTarget),

                // General
                Cast("Escape", escapeWhen => Global.CCBreak),// Excape
                Cast("Evasion", evasionWhen => Me.HealthPercent <= Global.Health.Low), // Dodge
                Cast("Shield Probe", shieldProbeWhen => Me.HealthPercent <= Global.Health.High), // Defense Screen
                Cast("Countermeasures", countermeasuresWhen => !Me.IsMirrorAbilityReady("Shield Probe", Me)),
				Cast("Cover Pulse", coverPulseWhen => Me.IsInCover() && Me.MobCountAround(Global.Distance.MeleeAoE) >= 1),
                //Cast("Ballistic Shield", ballisticShieldWhen => Global.IsInCover && Me.PlayerCountAround(1f) >= 3),
                Cast("Target Acquired", targetAcquiredWhen => Global.IsElite),
                Cast("Laze Target", lazeTargetWhen => Global.IsElite),
                Cast("Adrenaline Probe", adrenalineProbeWhen => Resource <= 65),
				//Cast("Adrenaline Probe", adrenalineProbeWhen => Resource <= 50 || Resource <= 70 && (Me.HasMirrorBuff("Target Acquired") || Me.HasMirrorBuff("Laze Target"))),
                //Cast("Countermeasures", countermeasuresWhen => !Me.IsMirrorAbilityReady("Shield Probe", Me)),

                new Decorator(whenCrowdControlNeeded => CCTarget != null,
                    Cast("Slice Droid", sliceDroidOn => CCTarget, sliceDroidWhen => TargetSelect.ViableTargetList().FirstOrDefault(t => t.HasMirrorDebuffStacks("Slice Droid")) == null)),

                // Aoe Rotation
                CastOnGround("Orbital Strike", orbitalStrikeOn => MyTarget.Position, orbitalStrikeWhen => (!Me.IsInParty() ? Me.MobCountAround(Global.Distance.MeleeAoE) >= 4 : MyTarget.MobCountAround(Global.Distance.MeleeAoE) >= 4)),
                Cast("Fragmentation Grenade", fragmentationGrenadeWhen => MyTarget.MobCountAround(Global.Distance.MeleeAoE) >= 3),
                // Suppressive Fire 35 Energy

                // CC
                Cast("Distraction", distractionWhen => MyTarget.IsCastTimeRemaining(TimeSpan.FromSeconds(1))),
                Cast("Flash Bang", flashBangWhen => Me.MobCountAround(Global.Distance.MeleeAoE) >= 2),
                Cast("Debilitate", debilitateWhen => Global.RequiresCrowdControl && MyTarget.Distance <= Global.Distance.Melee),

                // Solo Rotation
                Cast("Shatter Shot", shatterShotWhen => !MyTarget.HasMirrorDebuff("Armor Reduced (Physical)")), // Flourish Shot
                Cast("Takedown", takedownWhen => MyTarget.HealthPercent <= 30 && Resource >= 75),
                Cast("Series of Shots", seriesOfShotsWhen => Me.IsInCover() && Resource >= 80),
                Cast("Followthrough"),
                Cast("Ambush", ambushWhen => Me.IsInCover() && (Me.IsMirrorAbilityReady("Followthrough", MyTarget) || Resource >= 75)),
                Cast("Snipe", snipeWhen => Me.IsInCover() && (Me.IsMirrorAbilityReady("Followthrough", MyTarget) && Resource >= 80)),
                Cast("Explosive Probe", explosiveProbeWhen => Me.IsInCover() && Global.IsElite && Resource >= 80),
                Cast("Corrosive Dart", corrosiveDartWhen => Global.IsElite && !MyTarget.HasMirrorDebuff("Poisoned (Tech)") && Resource >= 80), // Vital Shot ( Bleeding (Tech) )
                Cast("Snipe", snipeWhen => Me.IsInCover() && Resource >= 80),
                Cast("Rifle Shot") // Fury of Bolts

                //TODO: Delete this once MoveAndCoverForTarget() verified to work.
                // Movement
                //CreateBTPS.MoveWithinRangeAndLoS(target => MyTarget, Global.Distance.Ranged)
                );
        }

        [Behavior(BehaviorType.OutOfCombat)]
        [Class(CharacterClass.Agent, AdvancedClass.Sniper, SkillTreeId.SniperMarksmanship)]
        [Class(CharacterClass.Smuggler, AdvancedClass.Gunslinger, SkillTreeId.GunslingerSharpshooter)]
        public static Composite SniperMarksmanship_GunslingerSharpshooter_OutOfCombat()
        {
            // NB: Apparently, BWcore will call this routine when in combat on occasion.  It is also called while we're pulling.
            return (new PrioritySelector(
                TargetSelect.CreateBTPS_UpdateForBattlefieldConditions(),
                new Decorator(oocBuffWhen => !Me.IsMounted,
                    new PrioritySelector(
                        // Only break cover when we're not in pull...
                        new Decorator(breakCoverWhen => !Me.InCombat && !TargetSelect.IsAtThePull(),
                            CreateBTPS.BreakCrouchOrCover())     // Prevents the 'stuck handler dance' if combat ends in crouch/cover
                        ))
                ));
        }
    }
}
